import UIKit
import Logging
import LibBase
import LibNetwork
import RxSwift
import LibService

public protocol LibMessageCenterDelegate: AnyObject {
    func didRegister(_ messageCenter: LibMessageCenter,
                     deviceToken: String,
                     completion: @escaping (_ result: Bool) -> Void)
    
    /// 重置推送未读数
    func didClearAppIconBadgeNumber(_ messageCenter: LibMessageCenter,
                                    completion: @escaping (_ result: Bool) -> Void)
    
    /// 消息中心未读数
    /// - Parameters:
    ///   - messageCenter: LibMessageCenter
    ///   - completion: completion callback
    func getUnreadCount(_ messageCenter: LibMessageCenter,
                        completion: @escaping (_ unreadCount: Int?) -> Void)
    
    /// 设置消息已读
    func read(_ messageCenter: LibMessageCenter,
              messageIds: [String],
              completion: @escaping (_ unreadCount: Int?) -> Void)
    
    /// 重置消息中心未读数
    /// - Parameters:
    ///   - messageCenter: LibMessageCenter
    ///   - completion: 重置回调
    func resetUnreadCount(_ messageCenter: LibMessageCenter,
                          completion: @escaping (_ result: Bool) -> Void)
}

public class LibMessageCenter: NSObject {
    public static let shared = LibMessageCenter()
    
    public var disposeBag = DisposeBag()
    
    public weak var delegate: LibMessageCenterDelegate? {
        didSet {
            if (ServiceManager.shared.authService?.authRepository.data != nil) {
                startUnreadCountTimer()
            }
        }
    }
    
    private var logger = Logger(label: "LibMessageCenter")
    
    // 前台接收消息
    public let messageWillPresent = PublishSubject<Message>()
    
    // 消息栏点击接收消息
    public let messageDidReceive = PublishSubject<Message>()
    
    public let unreadCount = BehaviorSubject<Int>(value: 0)
    
    private var unreadCountTimer: Timer?
    
    private var deviceToken: String?
    
    private override init() {
        super.init()
        
        Network.shared
            .reachabilityListener
            .filterDuplicates(first: (try? Network.shared.reachabilityListener.value()) ?? .unknown)
            .subscribe(onNext: { [weak self] status in
                guard case .reachable = status, let self = self, let deviceToken = self.deviceToken else {
                    return
                }
                
                self.doRegister(deviceToken: deviceToken)
            })
            .disposed(by: disposeBag)
        
        ServiceManager.shared
            .authService?.authRepository.dataObservable
            .filterDuplicates(first: ServiceManager.shared.authService?.authRepository.data)
            .subscribe(onNext: { [weak self] userModel in
                if userModel == nil {
                    self?.unreadCount.onNext(0)
                    self?.stopUnreadCountTimer()
                    
                    self?.clearAppIconBadgeNumber()
                } else {
                    self?.startUnreadCountTimer()
                }
            }).disposed(by: disposeBag)
        
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(applicationWillEnterForeground(_:)),
            name: UIApplication.willEnterForegroundNotification,
            object: nil)
    }
    
    @objc func applicationWillEnterForeground(_ notification: NSNotification) {
        clearAppIconBadgeNumber()
    }
    
    public func register(application: UIApplication) {
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.alert, .badge, .sound]) { [weak self] result, error in
            self?.logger.info("requestAuthorization \(result ? "ok" : "false")")
            if let error = error {
                self?.logger.info(Logger.Message(stringLiteral: error.localizedDescription))
            }
        }
        
        application.registerForRemoteNotifications()
    }
    
    public func register(deviceToken: Data) {
        let deviceTokenStr = deviceToken.ex.toHexString()
        self.deviceToken = deviceTokenStr
        
        doRegister(deviceToken: deviceTokenStr)
    }
    
    private func doRegister(deviceToken: String) {
        delegate?.didRegister(self, deviceToken: deviceToken) { [weak self] result in
            guard result else {
                return
            }
            
            self?.deviceToken = nil
        }
    }
    
    public func clearAppIconBadgeNumber() {
        delegate?.didClearAppIconBadgeNumber(self, completion: { result in
            UIApplication.shared.applicationIconBadgeNumber = -1
        })
    }
    
    public func getUnreadCount() {
        delegate?.getUnreadCount(self, completion: { [weak self] unreadCount in
            self?.unreadCount.onNext(unreadCount ?? 0)
        })
    }
    
    public func read(messageIds: [String]) {
        delegate?.read(self, messageIds: messageIds, completion: { [weak self] unreadCount in
            self?.unreadCount.onNext(unreadCount ?? 0)
        })
    }
    
    /// 重置消息中心未读数(0)
    /// - Parameters:
    ///   - messageCenter: LibMessageCenter
    ///   - completion: 重置回调
    public func resetUnreadCount() {
        delegate?.resetUnreadCount(self, completion: { [weak self] result in
            self?.unreadCount.onNext(0)
        })
    }
    
    private func startUnreadCountTimer() {
        unreadCountTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { [weak self] timer in
            self?.getUnreadCount()
        }
        
        unreadCountTimer?.fire()
    }
    
    private func stopUnreadCountTimer() {
        unreadCountTimer?.invalidate()
        unreadCountTimer = nil
    }
}

extension LibMessageCenter: UNUserNotificationCenterDelegate {
    public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        logger.info("willPresent")
        
        messageWillPresent(messageBody: notification.request.content.userInfo["body"] as? [AnyHashable: Any])
        
        completionHandler(UNNotificationPresentationOptions())
    }
    
    public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        logger.info("didReceive")
        
        messageDidReceive(messageBody: response.notification.request.content.userInfo["body"] as? [AnyHashable: Any])
        
        completionHandler()
    }
    
    public func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) {
        logger.info("openSettingsFor")
    }
    
    private func messageWillPresent(messageBody: [AnyHashable: Any]?) {
        guard let messageBody = messageBody, let message = Message(values: messageBody) else {
            return
        }
        
        messageWillPresent.onNext(message)
        
        getUnreadCount()
        clearAppIconBadgeNumber()
    }
    
    private func messageDidReceive(messageBody: [AnyHashable: Any]?) {
        guard let messageBody = messageBody, let message = Message(values: messageBody) else {
            return
        }
        
        messageDidReceive.onNext(message)
        
        getUnreadCount()
        clearAppIconBadgeNumber()
    }
}
